package com.cooksys.film_rental.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.cooksys.film_rental.dao.AddressDao;
import com.cooksys.film_rental.model.Address;
import com.cooksys.film_rental.model.City;
import com.cooksys.film_rental.model.Country;
import com.cooksys.film_rental.model.Customer;
import com.cooksys.film_rental.model.Staff;
import com.cooksys.film_rental.model.Store;

@Repository("AddressDao")
@Transactional
public class AddressDaoImpl implements AddressDao {

	@Autowired(required = true)
	private SessionFactory sessionFactory;

	/**
	 * 
	 * @return the current session from the internal {@link SessionFactory}
	 */
	public Session currentSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public Address save(Address address) {
		Session session = currentSession();
		Serializable id = session.save(address);
		return (Address) session.get(Address.class, id);

	}

	@Override
	public void update(Address address) {
		Session session = currentSession();
		session.update(address);

	}

	@Override
	public void delete(Address address) {
		Session session = currentSession();
		session.delete(address);

	}

	@Override
	public Address getAddressByAddressId(Short addressId) {
		Session session = currentSession();

		// returns a record from the CUSTOMER table as a Address object based
		// on the given addressId, the table's primary key
		String hql = "from Address where addressId = :addressId";
		Query query = session.createQuery(hql);
		query.setShort("addressId", addressId);

		return (Address) query.list().get(0);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Address> searchAddressesByCity(City city) {
		Session session = currentSession();

		// Selects all address objects from a given city
		String hql = "from Address a where a.city = :city";
		Query query = session.createQuery(hql);
		query.setEntity("city", city);

		return query.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Address> searchAddressesByCountry(Country country) {
		Session session = currentSession();

		// Selects all address objects from a given country
		String hql = "from Address a where a.city.country = :country";
		Query query = session.createQuery(hql);
		query.setEntity("country", country);

		return query.list();
	}

	@Override
	public Address getAddressByStore(Store store) {
		Session session = currentSession();

		// Selects the address object associated with a given store object
		String hql = "select s.address from Store s where s = :store";
		Query query = session.createQuery(hql);
		query.setEntity("store", store);

		return (Address) query.list().get(0);
	}

	@Override
	public Address getAddressByStaff(Staff staff) {
		Session session = currentSession();

		// Selects the address object associated with a given staff object
		String hql = "select s.address from Staff s where s = :staff";
		Query query = session.createQuery(hql);
		query.setEntity("staff", staff);

		return (Address) query.list().get(0);
	}

	@Override
	public Address getAddressByCustomer(Customer customer) {
		Session session = currentSession();

		// Selects the address object associated with a given customer object
		String hql = "select c.address from Customer c where c = :customer";
		Query query = session.createQuery(hql);
		query.setEntity("customer", customer);

		return (Address) query.list().get(0);
	}

	@Override
	public void saveOrUpdate(Address address) {
		Session session = currentSession();

		session.saveOrUpdate(address);

	}

	@Override
	public Address getAddressByInfoAndCity(String address, String address2,
			String district, String phone, String postalCode, City city) {
		Session session = currentSession();

		String hql = "from Address a where a.address = :address and a.address2 = :address2 and a.district = :district and a.phone = :phone and a.postalCode = :postalCode and a.city = :city";
		Query query = session.createQuery(hql);

		query.setString("address", address);
		query.setString("address2", address2);
		query.setString("district", district);
		query.setString("phone", phone);
		query.setString("postalCode", postalCode);
		query.setEntity("city", city);

		return (Address) query.uniqueResult();
	}

}
